/*
* Copyright (C) Microsoft. All rights reserved.  
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not 
* use this file except in compliance with the License.  You may obtain a copy 
* of the License at http://www.apache.org/licenses/LICENSE-2.0  
* 
* THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
* WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
* MERCHANTABLITY OR NON-INFRINGEMENT. 
*
* See the Apache License, Version 2.0 for specific language governing 
* permissions and limitations under the License.
*
*/
#include "pch.h"
#include <journal/app/keys.h>
#include <journal/views/input_references.h>
#include <journal/app/constants.h>
#include <journal/views/quad_renderer.h>

namespace journal { namespace view {


input_references::input_references() : _lastKey(-1)
{
    std::shared_ptr<g::iasset_manager> assetManager = constants::graphics()->getAssetManager();
    _touchTexture = assetManager->getOrCreateTextureFromFile(
        constants::graphics(),
        L"res\\touch.png", // TRACK: const
        g::pixel_format::fromSource
        );

    _font = assetManager->getOrCreateFont(
        constants::graphics(), 
        L"Segoe UI", 
        48,
        false // right to left
        );
}

void input_references::onRender()
{
    if (constants::references::showTouchPoints())
    {
        std::for_each(
            _activeTouchPoints.begin(),
            _activeTouchPoints.end(),
            [this](const std::pair<b::uint32, a::pointer_args>& p)
        {
            const a::pointer_args& args = p.second;

            std::shared_ptr<quad_renderer> quad = quad_renderer::singleton();

            DEBUG_CONSOLE_TRACE(boost::wformat(L"rendering touch point %i") % args.id);

            constants::graphics()->setAlphaBlend(g::enabled_state::enabled);
            constants::graphics()->setZBuffer(g::enabled_state::disabled);
            constants::graphics()->setCulling(g::cull_state::none);

            m::point2d position;

            position.x = args.point.x - constants::shellService()->windowSize().x / 2.f;
            position.y = -args.point.y + constants::shellService()->windowSize().y / 2.f;

            quad->render(
                0.8f,
                0,
                constants::shellService()->windowSize(),
                m::point2d(50, 50),
                position,
                _touchTexture
                );
        });
    }

    if (constants::references::showKeys() &&
        _lastKey != -1 && 
        _keyTimer.getElapsedMilliseconds() <= 1000)
    {
        std::shared_ptr<g::iengine> graphics = constants::graphics();

        b::wchar w[2];
        w[0] = _lastKey;
        w[1] = L'\0';
        b::wchar* pw = &w[0];

        // TRACK: hack
        // some special cases
        if (_lastKey == 192) pw = L"~";
        else if (_lastKey == 189) pw = L"-";
        else if (_lastKey == 187) pw = L"+";
        else if (_lastKey == 27) { pw = L"ESC"; }
        else if (_lastKey == 37) { pw = L"LEFT"; }
        else if (_lastKey == 39) { pw = L"RIGHT"; }
        else if (_lastKey == 38) { pw = L"UP"; }
        else if (_lastKey == 40) { pw = L"DOWN"; }
        boost::wformat fmt = boost::wformat(L"%s") % pw;
        std::wstring ws = fmt.str();

        if (wcslen(pw) == 0)
        {
            return;
        }

        g::viewport vp;
        graphics->getViewport(&vp);

        // measure the text's rect
        m::rectangle textRect;
        _font->measureText(
            ws.c_str(),
            g::horizontal_alignment::right,
            g::vertical_alignment::top,
            false,
            &textRect
            );

        textRect.top += vp.height - 70;
        textRect.bottom += vp.height - 70;
        textRect.left += vp.width - 10;
        textRect.right += vp.width - 10;

        // draw backdrop rectangle
        m::rectangle backdropRect(textRect);
        backdropRect.top -= 3;
        backdropRect.bottom += 1;
        backdropRect.left -= 4;
        backdropRect.right += 2;
            
        std::shared_ptr<g::ieffect2> effect;
        effect = graphics->getStandardEffect(g::standard_effect::screenColored);

        effect->begin(graphics);
        graphics->setAlphaBlend(g::enabled_state::enabled);
        graphics->setZBuffer(g::enabled_state::disabled);
        graphics->setCulling(g::cull_state::none);

        graphics->beginScreenSpace(g::primitive_type::triangleStrip);

        graphics->setColor(g::packColor(128, 255, 0, 0));

        m::point4d pos1(backdropRect.left-0.5f, backdropRect.top-0.5f, 1.0f);
        graphics->setScreenSpaceVertex(pos1);

        m::point4d pos2(backdropRect.right-0.5f, backdropRect.top-0.5f, 1.0f);
        graphics->setScreenSpaceVertex(pos2);

        graphics->setColor(g::packColor(128, 255, 0, 0));

        m::point4d pos4(backdropRect.left-0.5f, backdropRect.bottom-0.5f, 1.0f);
        graphics->setScreenSpaceVertex(pos4);

        m::point4d pos3(backdropRect.right-0.5f, backdropRect.bottom-0.5f, 1.0f);
        graphics->setScreenSpaceVertex(pos3);

        graphics->end();

        effect->end(graphics);

        static const g::packed_color textColor = g::packColor(255,255,255,255);
        textRect.right -= 2;
        textRect.top -= 2;
        _font->renderText(
            graphics,
            ws.c_str(),
            textColor,
            g::horizontal_alignment::left,
            g::vertical_alignment::top,
            &textRect
            );
    }
}

void input_references::onKey(const a::key_args& args, void* context)
{
    if (!constants::references::showKeys())
    {
        return;
    }

    _lastKey = args.vk;
    _keyTimer.reset();
}

void input_references::onPointer(const a::pointer_args& args, void* context)
{
    if (!constants::references::showTouchPoints())
    {
        return;
    }

    // TRACK: slow.  we don't want to do this for every event...
    if (args.deviceType == a::device_type::touch)
    {
        if (args.type == a::pointer_event_type::down)
        {
            auto it = _activeTouchPoints.find(args.id);
            if (it == _activeTouchPoints.end())
            {
                _activeTouchPoints[args.id] = args;
            }
        }
        else if (args.type == a::pointer_event_type::up)
        {
            auto it = _activeTouchPoints.find(args.id);
            if (it != _activeTouchPoints.end())
            {
                _activeTouchPoints.erase(it);
            }
        }
        else if (args.type == a::pointer_event_type::move)
        {
            auto it = _activeTouchPoints.find(args.id);
            if (it != _activeTouchPoints.end())
            {
                _activeTouchPoints[args.id] = args;
            }
        }
    }
}

}} // namespace journal::view